﻿using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Reflection;
using System.Windows;
using System.Windows.Input;
using CredentialsManager.Helpers;
using CredentialsManager.Properties;
using MVVMFoundation;
using CredentialsManager.Common;

namespace CredentialsManager.ViewModels
{
    public class ResetPasswordViewModel : PasswordViewModel
    {
        #region Private classes

        private class ResetWorkerInput : SetupWorkerInput
        {
            public bool RequiresQuestionAndAnswer { get; set; }
            public string PasswordAnswer { get; set; }
        }

        #endregion

        #region Private member variables

        private BackgroundWorker m_ResetWorker;
        private bool m_IsPasswordReset;
        private RelayCommand m_ResetCommand;

        #endregion

        #region Constructor

        public ResetPasswordViewModel(PasswordSettings passwordSettings,
            string application, string userName)
            : this(passwordSettings, application, userName, Resources.ResetPasswordWindowTitle)
        { }

        public ResetPasswordViewModel(PasswordSettings passwordSettings,
            string application, string userName, string displayName)
            : base(displayName, userName, application, passwordSettings)
        {
            this.IsPasswordReset = false;

            m_ResetWorker = new BackgroundWorker();
            m_ResetWorker.Initialise(m_ResetWorker_DoWork,
                m_ResetWorker_RunWorkerCompleted, null, false);
        }

        #endregion

        #region Background worker handlers

        private void m_ResetWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            var input = e.Argument as ResetWorkerInput;
            Debug.Assert(input != null);

            var proxy = ProxyFactory.Create<PasswordManagerClient, IPasswordManager>(
                ServiceAddressList.CredentialsService);

            try
            {
                if (input.RequiresQuestionAndAnswer)
                {
                    e.Result = proxy.ResetPasswordWithQuestionAndAnswer(input.Application,
                        input.UserName, input.PasswordAnswer);
                }
                else
                {
                    e.Result = proxy.ResetPassword(input.Application, input.UserName);
                }
            }
            finally
            {
                ProxyFactory.Cleanup<PasswordManagerClient, IPasswordManager>(proxy);
            }
        }

        private void m_ResetWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                ErrorHandler.HandleNonSpecificWCFException(e.Error, this.DisplayName);
            }
            else
            {
                Debug.Assert(e.Result != null && !string.IsNullOrEmpty(e.Result.ToString()));
                this.Password = e.Result.ToString();
                Clipboard.SetText(this.Password);
                this.IsPasswordReset = true;
            }

            this.IsLoading = false;
        }

        #endregion

        #region Public properties

        public bool IsPasswordReset
        {
            get
            {
                return m_IsPasswordReset;
            }
            private set
            {
                m_IsPasswordReset = value;
                RaisePropertyChanged(MethodBase.GetCurrentMethod().GetPropertyName());
            }
        }

        #endregion

        #region Protected methods

        protected override void Validate()
        {
            this.IsValid = true;

            if (this.PasswordSettings.RequiresQuestionAndAnswer)
            {
                this.IsValid = (!string.IsNullOrEmpty(this.SecurityQuestion) &&
                    this.SecurityQuestion.Trim() != string.Empty);
            }
        }

        protected override void HandleNoPasswordQuestion()
        {
            string message = Resources.CannotChangePasswordNoSecurityQuestionErrorMessage;
            var messageBox = base.GetService<IMessageBoxService>();
            Debug.Assert(messageBox != null);
            messageBox.Show(message, this.DisplayName, MessageBoxButton.OK, MessageBoxImage.Exclamation);
            this.OnRequestClose();
        }

        #endregion

        #region Public methods

        public void ResetPassword()
        {
            if (!this.IsValid)
            {
                throw new InvalidOperationException(
                    Resources.CannotResetPasswordInvalidOperationException);
            }

            if (this.IsPasswordReset)
            {
                throw new InvalidOperationException(
                    Resources.PasswordAlreadyResetInvalidOperationException);
            }

            var input = new ResetWorkerInput()
            {
                Application = this.Application,
                PasswordAnswer = this.SecurityAnswer,
                RequiresQuestionAndAnswer = this.RequiresQuestionAndAnswer,
                UserName = this.UserName
            };

            this.IsLoading = true;
            this.ProgressMessage = string.Format(Resources.ResetPasswordProgressMessage.ToString(),
                this.UserName);
            m_ResetWorker.RunWorkerAsync(input);
        }

        #endregion

        #region Commands

        public ICommand ResetCommand
        {
            get
            {
                return m_ResetCommand ?? (m_ResetCommand = new RelayCommand(
                    param => this.ResetPassword()));
            }
        }

        #endregion
    }
}
